package com.wzcl.app.service.impl;

import com.wzcl.app.dao.model.*;
import com.wzcl.app.dao.repository.*;
import com.wzcl.app.model.common.*;
import com.wzcl.app.model.dto.CourseDto;
import com.wzcl.app.model.vo.CourseVo;
import com.wzcl.app.model.vo.StudyDataVo;
import com.wzcl.app.service.CommodityService;
import com.wzcl.app.service.CourseService;
import com.wzcl.app.service.GradeService;
import com.wzcl.app.service.SubjectService;
import com.wzcl.app.utils.CollectionUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Log4j2
@Service
@Transactional
public class CourseServiceImpl implements CourseService {
    @Resource
    private CourseRepository repository;
    @Resource
    private SubjectService subjectService;
    @Resource
    private GradeService gradeService;
    @Resource
    private CommodityService commodityService;
    @Resource
    private CourseRepository courseRepository;
    @Resource
    private AppUserRepository appUserRepository;
    @Resource
    private EssayCourseCatalogRepository catalogRepository;
    @Resource
    private CatalogEvaluateScoreRepository catalogEvaluateScoreRepository;
    @Resource
    private CatalogTaskRepository catalogTaskRepository;
    @Resource
    private UserTaskQuizAnswerRepository userTaskQuizAnswerRepository;
    @Resource
    private EssayCourseQuestionBankRepository essayCourseQuestionBankRepository;
    @Resource
    private CourseTeacherRepository courseTeacherRepository;
    @Resource
    private CatalogTaskRepository taskRepository;

    @Override
    public Course addCourse(CourseDto courseDto) {
        Course course = new Course();
        course.setSubject(subjectService.getAndCheckById(courseDto.getSubjectId()));
        course.setGrade(gradeService.getAndCheckById(courseDto.getGradeId()));
        BeanUtils.copyProperties(courseDto, course, "id", "state", "courseState");
        if (courseDto.getDate() != null) {
            course.setStartDate(courseDto.getDate()[0]);
            course.setEndDate(courseDto.getDate()[1]);
        }
        if (courseDto.getTime() != null) {
            course.setStartTime(courseDto.getTime()[0]);
            course.setEndTime(courseDto.getTime()[1]);
        }
        if (courseDto.getPictures() != null && courseDto.getPictures().size() > 0) {
            course.setPictures(StringUtils.join(courseDto.getPictures(), ","));
        }
        course.setHaveBook(false);
        course.setRealSaleVolume(0);
        course.setRealViewVolume(0l);
        course.setCourseState(WZCL.COURSE_STATE.NOT_START);
        course.setState(WZCL.STATE.NOT_DELETE);
        return repository.save(course);
    }

    @Override
    public Course delCourseById(Integer id) {
        //校验获取
        Course course = getAndCheckById(id);
        //删除课程需要先删除所在的商品
        commodityService.delCommodityByResource(course.getId(), WZCL.COMMODITY_TYPE.COURSE);
        //删除
        course.setState(WZCL.STATE.IS_DELETE);
        repository.save(course);
        return course;
    }

    @Override
    public void addCourseCommodity(Commodity commodity) {
        //校验获取
        Course course = getAndCheckById(commodity.getResourceId());
        //校验商品是否重复
        if (course.getCommodity() != null) {
            throw new BusinessException(CodeMsg.SYSTEM_ERR, "该产品已发布商品,无法上线新商品");
        }
        course.setCommodity(commodity);
        repository.save(course);
    }

    @Override
    public void delCourseCommodityById(Integer id) {
        //校验获取
        Course course = getAndCheckById(id);
        //删除
        course.setCommodity(null);
        repository.save(course);
    }

    @Override
    public Course updateCourse(CourseDto courseDto) {
        //校验获取
        Course course = getAndCheckById(courseDto);
        //修改
        BeanUtils.copyProperties(courseDto, course, "id", "state", "courseState");
        if (courseDto.getDate() != null) {
            course.setStartDate(courseDto.getDate()[0]);
            course.setEndDate(courseDto.getDate()[1]);
        }
        if (courseDto.getSubjectId() != null) {
            course.setSubject(subjectService.getSubjectById(courseDto.getSubjectId()));
        }
        if (courseDto.getGradeId() != null) {
            course.setGrade(gradeService.getGradeById(courseDto.getGradeId()));
        }
        if (courseDto.getPictures() != null && courseDto.getPictures().size() > 0) {
            course.setPictures(StringUtils.join(courseDto.getPictures(), ","));
        }
        return repository.save(course);
    }

    @Override
    public Course getCourseById(Integer id) {
        return repository.findById(id).orElse(null);
    }

    @Override
    public Course getAndCheckById(Integer id) {
        if (id == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少课程Id");
        }
        Course course = getCourseById(id);
        if (course == null) {
            throw new BusinessException(CodeMsg.COURSE_NOT_EXIST);
        }
        if (!WZCL.STATE.NOT_DELETE.equals(course.getState())) {
            throw new BusinessException(CodeMsg.COURSE_IS_DELETE);
        }
        return course;
    }


    @Override
    public Course getAndCheckByCommodityId(Integer id) {
        if (id == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少商品ID");
        }
        Course course = repository.findByCommodityId(id);
        if (course == null) {
            throw new BusinessException(CodeMsg.COURSE_NOT_EXIST);
        }
        return course;
    }

    @Override
    public List<Course> getCourseById(List<Integer> ids) {
        return repository.findAllById(ids);
    }

    @Override
    public List<Course> getCourseList(CourseDto courseDto) {
        return repository.findAll(getSpecification(courseDto), courseDto.getSort());
    }

    public MyPage<Course> getCoursePage(CourseDto courseDto) {
        Page<Course> all = repository.findAll(getSpecificationPage(courseDto), courseDto.getPageable());
        return new MyPage<>(all);
    }

    //getPage筛选条件
    private Specification<Course> getSpecificationPage(CourseDto courseDto) {
        return new Specification<Course>() {
            @Override
            public Predicate toPredicate(Root<Course> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (courseDto.getId() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("id"), courseDto.getId()));
                }
                if (courseDto.getGradeId() != null) {
                    Join<Course, Grade> gradePath = root.join("grade");
                    predicates.add(criteriaBuilder.equal(gradePath.get("id"), courseDto.getGradeId()));
                }
                if (StringUtils.isNotBlank(courseDto.getName())) {
                    predicates.add(criteriaBuilder.like(root.get("name"), "%" + courseDto.getName() + "%"));
                }
                if (courseDto.getCourseType() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("courseType"), courseDto.getCourseType()));
                }
                if (courseDto.getIsCommodity() != null) {
                    if (courseDto.getIsCommodity()) {
                        Join<Course, Commodity> commodityPath = root.join("commodity");
                        predicates.add(criteriaBuilder.equal(commodityPath.get("sale"), true));
                    } else {
                        predicates.add(criteriaBuilder.isNull(root.get("commodity")));
                    }
                }
                if (courseDto.getSubjectId() != null) {
                    Join<Course, Subject> subjectPath = root.join("subject");
                    predicates.add(criteriaBuilder.equal(subjectPath.get("id"), courseDto.getSubjectId()));
                }
                predicates.add(criteriaBuilder.equal(root.get("state"), WZCL.STATE.NOT_DELETE));
                // 排序
                criteriaQuery.orderBy(criteriaBuilder.desc(root.get("viewVolume")));
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }

    @Override
    public Course saveCourse(Course course) {
        return repository.save(course);
    }

    @Override
    public void viewCourse(Integer id) {
        try {
            Course course = getCourseById(id);
            course.setRealViewVolume(course.getRealViewVolume() + 1);
            repository.save(course);
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }
    }

    @Override
    public List<Course> retrieveCourseByType(CourseDto courseDto) {
        List<Course> courses = repository.findBySomeType(courseDto.getName());
        for (int index = 0; index < courses.size(); index++) {
            if (courses.get(index).getCommodity() == null || courses.get(index).getCommodity().getSale() == false) {
                courses.remove(index);
                index --;
            }
        }
        //对排序结果分页
        List<Course> listByPage = CollectionUtil.getListByPage(courses, courseDto.getPageNumber()+1, courseDto.getPageSize());
        return listByPage;
    }

    @Override
    public RVO retrieveByUserId() {
        String phone = SecurityContextHolder.getContext().getAuthentication().getName();
        //查询用户id
        AppUser appUser = appUserRepository.findByPhone(phone);
        //首先判断用户是不是教师
        if (appUser.getType() == 2){
            RVO.error("该用户不是教师");
        }
        //判断该教师的职位是否是授课教师
        List<Integer> courseIdList = courseTeacherRepository.findAllByUserId(appUser.getId());
        //筛选作文课（由于两张表之前没有关联，所以只能这样手动筛选，我也很无奈啊）
        List<Course> list = new ArrayList<>();
        for (int index = 0; index < courseIdList.size(); index++) {
            Course course = courseRepository.findAllByCourseId(courseIdList.get(index));
            if (course.getCourseType() == 10){
                list.add(course);
            }
        }
        return RVO.success(list);
    }

    @Override
    public List<EssayCourseCatalog> retrieveByCourseId(Integer courseId) {
        String phone = SecurityContextHolder.getContext().getAuthentication().getName();
        AppUser appUser = appUserRepository.findByPhone(phone);
        //查询当前课程下所有章节
        List<EssayCourseCatalog> catalogList = catalogRepository.findAllByCourseId(courseId);
        //筛选出当前课程下已完成章节
        for (int index = 0; index < catalogList.size(); index++) {
            CatalogEvaluateScore catalogEvaluateScore = catalogEvaluateScoreRepository.findEvaluateByCatalogId(catalogList.get(index).getId(), appUser.getId());
            if (catalogEvaluateScore == null){
                catalogList.remove(index);
                index--;
            }

        }
        return catalogList;
    }

    @Override
    public StudyDataVo retrieveStudyDataByCourseId(Integer courseId) {
        String phone = SecurityContextHolder.getContext().getAuthentication().getName();
        StudyDataVo studyData = new StudyDataVo();
        List <Integer> taskIdAll = new ArrayList<>();
        List<EssayCourseCatalog> catalogList = retrieveByCourseId(courseId);
        //统计本课程下已学习章节数量
        studyData.setCatalogStudyCount(catalogList.size());
        //查询当前章课程下所有章节id
        List<EssayCourseCatalog> catalogAllList = catalogRepository.findAllByCourseId(courseId);
        //查询出章节下的所有任务id
        for (int index = 0; index < catalogAllList.size(); index++) {
            List<Integer> taskIds = catalogTaskRepository.findTaskIdByCatalogId(catalogAllList.get(index).getId());
            taskIdAll.addAll(taskIds);
        }
        Integer audioStudyCount = 0;
        Integer questionStudyCount = 0;
        //筛选出答题记录中已经回答过的题
        for (int index = 0; index < taskIdAll.size(); index++) {
            List<UserTaskQuizAnswer> questionByAnswer = userTaskQuizAnswerRepository.getQuestionByAnswer(taskIdAll.get(index), phone);
            if (questionByAnswer != null){
                questionStudyCount++;
                //判断是否是语音题
                //根据taskId查询任务下的题目
                String questionList = catalogTaskRepository.findByTaskId(taskIdAll.get(index)).getQuestionList();
                //任务下的题目解析
                List<String> listFromString = CollectionUtil.getListFromString(questionList, ",");
                System.out.println(listFromString);
                for (int inner = 0; inner < listFromString.size(); inner++) {
                    if (essayCourseQuestionBankRepository.findQuestionBankById(Integer.valueOf(listFromString.get(inner))).getAudio() != null){
                        audioStudyCount++;
                    }
                }
            }
        }
        studyData.setQuestionStudyCount(questionStudyCount);
        studyData.setAudioStudyCount(audioStudyCount);
        return studyData;
    }

    private Specification<Course> getSpecification(CourseDto courseDto) {
        return new Specification<Course>() {
            @Override
            public Predicate toPredicate(Root<Course> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (courseDto.getId() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("id"), courseDto.getId()));
                }
                if (courseDto.getGradeId() != null) {
                    Join<Course, Grade> gradePath = root.join("grade");
                    predicates.add(criteriaBuilder.equal(gradePath.get("id"), courseDto.getGradeId()));
                }
                if (courseDto.getSubjectId() != null) {
                    Join<Course, Subject> subjectPath = root.join("subject");
                    predicates.add(criteriaBuilder.equal(subjectPath.get("id"), courseDto.getSubjectId()));
                }
                if (StringUtils.isNotBlank(courseDto.getName())) {
                    predicates.add(criteriaBuilder.like(root.get("name"), "%" + courseDto.getName() + "%"));
                }
                if (courseDto.getIsCommodity() != null) {
                    if (courseDto.getIsCommodity()) {
                        Join<Course, Commodity> commodityPath = root.join("commodity");
                        predicates.add(criteriaBuilder.equal(commodityPath.get("sale"), true));
                    } else {
                        predicates.add(criteriaBuilder.isNull(root.get("commodity")));
                    }
                }
                if (courseDto.getHard() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("hard"), courseDto.getHard()));
                }
                if (courseDto.getCourseType() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("courseType"), courseDto.getCourseType()));
                }
                predicates.add(criteriaBuilder.equal(root.get("state"), WZCL.STATE.NOT_DELETE));
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }

    @Override
    public List<CatalogTask> getAllTaskByCourse(Integer courseId){
        List<CatalogTask> taskAllList = new ArrayList<>();
        List<EssayCourseCatalog> catalogList = catalogRepository.findAllByCourseId(courseId);
        for (int index = 0; index < catalogList.size(); index++) {
            List<CatalogTask> taskList = taskRepository.findAllCatalog(catalogList.get(index).getId());
            taskAllList.addAll(taskList);
        }
        return taskAllList;
    }

    @Override
    public List<EssayCourseCatalog> getAllCatalogByCourse(Integer courseId) {
        String phone = SecurityContextHolder.getContext().getAuthentication().getName();
        List<EssayCourseCatalog> catalogList = catalogRepository.findAllByCourseId(courseId);
        for (int index = 0; index < catalogList.size(); index++) {
            CatalogEvaluateScore catalogEvaluateScore = catalogEvaluateScoreRepository.findEvaluateByCatalogId(catalogList.get(index).getId(), appUserRepository.findByPhone(phone).getId());
            if (catalogEvaluateScore == null){
                catalogList.remove(index);
                index --;
            }
        }
        return catalogList;
    }
}